package com.spring.theory.aop.advice;

import java.lang.reflect.Method;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.StaticMethodMatcherPointcut;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.transaction.annotation.Transactional;

/**
 * aop 1-2 切点的匹配
 */
@Slf4j
public class TestPointcut {
    public static void main(String[] args) throws NoSuchMethodException {
        AspectJExpressionPointcut pt1 = new AspectJExpressionPointcut();
        //底层都是 MethodMatcher 接口
        /**
         * 1. execution 可以匹配方法信息
         */
        pt1.setExpression("execution(* test1())");

        boolean m1 = pt1.matches(T1.class.getMethod("test1"), T1.class);
        boolean m1_2 = pt1.matches(T1.class.getMethod("test2"), T1.class);
        log.info("m1是否匹配 = {}", m1);
        log.info("m1_2是否匹配 = {}", m1_2);

        /**
         * 2. @annotation(注解全路径)，匹配是方法上是否有对应注解
         */
        AspectJExpressionPointcut pt2 = new AspectJExpressionPointcut();
        pt2.setExpression("@annotation(org.springframework.transaction.annotation.Transactional)");

        boolean m2 = pt2.matches(T1.class.getMethod("test1"), T1.class);
        boolean m2_2 = pt2.matches(T1.class.getMethod("test2"), T1.class);
        log.info("m2是否匹配 = {}", m2);
        log.info("m2_2是否匹配 = {}", m2_2);

        /**
         * 3. 匹配类上的信息
         */
        StaticMethodMatcherPointcut pt3 = new StaticMethodMatcherPointcut() {
            @Override
            public boolean matches(Method method, Class<?> targetClass) {
                /**
                 * MergedAnnotations spring提供读取注解信息的工具类
                 */
                MergedAnnotations annotations = MergedAnnotations.from(method);
                if (annotations.isPresent(Transactional.class)) {
                    return true;
                }
                // 检查类上是否存在对应注解；使用可以查找继承类和接口实现类的
                annotations = MergedAnnotations.from(targetClass, SearchStrategy.TYPE_HIERARCHY);
                if (annotations.isPresent(Transactional.class)) {
                    return true;
                }

                return false;
            }
        };
        boolean m3 = pt3.matches(T1.class.getMethod("test1"), T1.class);
        boolean m3_1 = pt3.matches(T1.class.getMethod("test2"), T1.class);
        boolean m3_2 = pt3.matches(T2.class.getMethod("test1"), T2.class);
        boolean m3_3 = pt3.matches(T3.class.getMethod("i3"), T3.class);

        log.info("m3是否匹配 = {}", m3);
        log.info("m3_1是否匹配 = {}", m3_1);
        log.info("m3_2是否匹配 = {}", m3_2);
        log.info("m3_3是否匹配 = {}", m3_3);


    }

    static class T1 {

        @Transactional
        public void test1() {

        }

        public void test2() {

        }
    }

    @Transactional
    static class T2 {
        public void test1() {

        }
    }

    @Transactional
    interface I3 {
        void i3();
    }

    static class T3 implements I3 {
        @Override
        public void i3() {

        }
    }


}
